package com.perfma.util;

import com.perfma.util.model.*;
import com.perfma.util.service.MinioStorageServiceImpl;
import com.perfma.util.service.StorageService;
import com.perfma.util.tool.FileUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Properties;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author: junhui.si
 * @date: 2023-07-06 14:37
 **/
public class FastDFSUtil {
    private static StorageService client;

    private static final Object lock = new Object();

    private static boolean inited = false;

    private static volatile ReentrantLock reentrantLock;

    /**
     * 若文件名中不存在. 则直接返回txt类型
     *
     * @param name 文件的原名称
     * @return 后缀名
     */
    public static String getExt(String name) {
        if (StringUtils.isEmpty(name)) {
            return "txt";
        }

        if (!name.contains(".")) {
            return "txt";
        }
        String[] tmp = name.split("\\.");
        return tmp[tmp.length - 1];
    }

    public static StorageService getClient() throws IOException {
        if (client == null) {
            synchronized (lock) {
                if (!inited) {
                    reentrantLock = new ReentrantLock();
                    inited = true;
                }
                if (client == null) {
                    File file = new File("perfma/config/perfma-fastdfs-connector.properties");
                    InputStream in = Files.newInputStream(Paths.get("perfma/config/perfma-fastdfs-connector.properties"));
                    System.out.println(file.getAbsolutePath());
                    Properties properties = new Properties();
                    properties.load(in);

                    StorageProperties storageProperties = new StorageProperties();
                    StorageProperties.MinioConfig minioConfig = new StorageProperties.MinioConfig();
                    // 例：10.10.222.151:9700
                    minioConfig.setEndpoint(properties.getProperty("minio.address"));

                    String secretKey = properties.getProperty("minio.secretKey");
                    secretKey = secretKey == null ? "Perfma888." : secretKey;
                    minioConfig.setSecretKey(secretKey);

                    String accessKey = properties.getProperty("minio.accessKey");
                    accessKey = accessKey == null ? "minio" : accessKey;
                    minioConfig.setAccessKey(accessKey);

                    String bucketName = properties.getProperty("minio.bucketName");
                    bucketName = bucketName == null ? "default" : bucketName;
                    minioConfig.setBucketName(bucketName);
                    storageProperties.setMinio(minioConfig);
                    client = new MinioStorageServiceImpl(storageProperties);
                }
            }
        }
        reentrantLock.lock();
        return client;
    }

    public static String uploadFile(byte[] buff, String extName) throws Exception {
        try {
            UploadRequest uploadRequest = new UploadRequest();
            uploadRequest.setUploadBytes(buff);
//            uploadRequest.setFileName(extName);
            String ret = getClient().upload(uploadRequest);
            if (StringUtils.isEmpty(ret)) {
                throw new RuntimeException("上传内容到文件服务器返回空filekey");
            }
            return ret;
        } finally {
            reentrantLock.unlock();
        }
    }

    public static String uploadFile(String localFilename, String extName) throws Exception {
        try {
            UploadRequest uploadRequest = new UploadRequest();
//            uploadRequest.setFileName(extName);
            uploadRequest.setUploadFile(new File(localFilename));
            return getClient().upload(uploadRequest);
        } finally {
            reentrantLock.unlock();
        }
    }

    public static String uploadAppendFile(byte[] buff, String extName) throws Exception {
        return uploadFile(buff, extName);
    }

    public static String uploadAppendFile(String localFilename, String extName) throws Exception {
        return uploadFile(localFilename, extName);
    }

    public static void append(String appenderFileId, byte[] fileBuf) throws Exception {
        try {
            AppendUploadRequest appendUploadRequest = new AppendUploadRequest();
            appendUploadRequest.setFileKey(appenderFileId);
            appendUploadRequest.setUploadBytes(fileBuf);
            getClient().appendUpload(appendUploadRequest);
        } finally {
            reentrantLock.unlock();
        }
    }

    public static int truncate(String appenderFileId) throws Exception {
        try {
            TruncateUploadRequest truncateUploadRequest = new TruncateUploadRequest();
            truncateUploadRequest.setFileKey(appenderFileId);
            truncateUploadRequest.setUploadBytes(new byte[0]);
            getClient().truncateUpload(truncateUploadRequest);
            return 0;
        } catch (Exception e) {
            return -1;
        } finally {
            reentrantLock.unlock();
        }
    }

    public static int downloadFile(String key, String localFilename) throws Exception {
        try {
            FileUtil.mkdirs(new File(localFilename).getParent());
            DownloadRequest downloadRequest = new DownloadRequest();
            downloadRequest.setFileKey(key);
            downloadRequest.setOutputFile(new File(localFilename));
            getClient().download(downloadRequest);
            return 0;
        } catch (Exception e) {
            return -1;
        } finally {
            reentrantLock.unlock();
        }
    }

    public static byte[] downloadByte(String key) throws Exception {
        try {
            DownloadRequest downloadRequest = new DownloadRequest();
            downloadRequest.setFileKey(key);
            File tempFile = createTempFile();
            downloadRequest.setOutputFile(tempFile);
            getClient().download(downloadRequest);
            byte[] fileBytes = FileUtils.readFileToByteArray(tempFile);

            tempFile.delete();
            return fileBytes;

        } finally {
            reentrantLock.unlock();
        }
    }

    public static int downloadFile(String key, long file_offset, long download_bytes, String localFilename) throws Exception {
        try {
            FileUtil.mkdirs(new File(localFilename).getParent());
            DownloadRequest downloadRequest = new DownloadRequest();
            downloadRequest.setFileKey(key);
            downloadRequest.setOffset(file_offset);
            downloadRequest.setLength(download_bytes);
            downloadRequest.setOutputFile(new File(localFilename));
            getClient().download(downloadRequest);
            return 0;
        } finally {
            reentrantLock.unlock();
        }
    }

    public static byte[] downloadByte(String key, long file_offset, long download_bytes) throws IOException {
        try {
            DownloadRequest downloadRequest = new DownloadRequest();
            downloadRequest.setFileKey(key);
            downloadRequest.setOffset(file_offset);
            downloadRequest.setLength(download_bytes);
            File tempFile = createTempFile();
            downloadRequest.setOutputFile(tempFile);
            getClient().download(downloadRequest);
            byte[] fileBytes = FileUtils.readFileToByteArray(tempFile);
            try {
                tempFile.delete();
            } catch (Exception e) {
                e.printStackTrace();
//            logger.debug("[文件下载-临时文件删除失败]， ，file:{}", key);
            }
            return fileBytes;
        } finally {
            reentrantLock.unlock();
        }
    }

    public static int safeDeleteFile(String key) throws Exception {
        if (StringUtils.isEmpty(key)) {
            return 1;
        }
        FileInfo fileInfo = queryFileInfo(key);
        if (fileInfo == null) {
            return 1;
        }

        return deleteFile(key);
    }

    public static int deleteFile(String key) throws IOException {
        try {
            if (StringUtils.isEmpty(key)) {
                return 1;
            }
            getClient().deleteFile(key);
            return 0;
        } finally {
            reentrantLock.unlock();
        }
    }

    public static FileInfo fileExist(String key) throws Exception {
        return queryFileInfo(key);
    }

    public static FileInfo queryFileInfo(String key) throws Exception {
        try {
            if (key == null) {
                return null;
            }
            return getClient().getFileInfo(key);
        } finally {
            reentrantLock.unlock();
        }
    }

    private static File createTempFile() throws IOException {
        return File.createTempFile("xsea_tempfile", null);
    }
}
